home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 15 / Amiga Plus Leser CD 15.iso / Tools / Development / mmu / MuManual / C_Sources / MuFastZero.c < prev    next >
C/C++ Source or Header  |  2002-03-12  |  44KB  |  1,193 lines

  1. /*****************************************************************
  2.  ** MuFastZero                                                  **
  3.  **                                                             **
  4.  ** A MMU library compatible zeropage remapper                  **
  5.  ** Version 40.20 28.4.2001 © THOR-Software, by Thomas Richter  **
  6.  *****************************************************************/
  7.  
  8. /// Includes
  9. #include <exec/types.h>
  10. #include <exec/memory.h>
  11. #include <exec/ports.h>
  12. #include <exec/execbase.h>
  13. #include <dos/dos.h>
  14. #include <mmu/mmubase.h>
  15. #include <mmu/context.h>
  16. #include <mmu/mmutags.h>
  17. #include <workbench/startup.h>
  18.  
  19. #include <proto/exec.h>
  20. #include <proto/mmu.h>
  21. #include <proto/dos.h>
  22. #include <proto/icon.h>
  23.  
  24. #include <string.h>
  25. #include <dos.h>
  26. ///
  27. /// Defines
  28. #define STRINGDATE "21.7.2001"
  29. #define STRINGVERSION "40.20"
  30. #define CACHEFLAGS (MAPP_CACHEINHIBIT|MAPP_COPYBACK|MAPP_NONSERIALIZED|MAPP_IMPRECISE)
  31.  
  32. #define TEMPLATE "ON=FASTZERO/S,OFF=NOFASTZERO/S,FASTEXEC/S,FORCENATIVE/S,MOVESSP=FASTSSP/S,STACKSIZE/K/N,MOVEVBR=FASTVBR/S,CLEARVBR/S,IGNORE/S"
  33.  
  34. #define OPT_ON  0
  35. #define OPT_OFF 1
  36. #define OPT_FASTEXEC 2
  37. #define OPT_FORCENATIVE 3
  38. #define OPT_FASTSSP 4
  39. #define OPT_STACKSIZE 5
  40. #define OPT_FASTVBR 6
  41. #define OPT_CLEARVBR 7
  42. #define OPT_IGNORE 8
  43. #define OPT_WINDOW 9
  44. #define OPT_COUNT 10
  45.  
  46. #define LVO_SUMKICKDATA -612
  47. ///
  48. /// Statics
  49. struct MMUBase *MMUBase;
  50. struct DosLibrary *DOSBase;
  51. struct ExecBase *SysBase;
  52. struct Library *IconBase;
  53. ///
  54. /// Protos
  55. int __asm __saveds main(void);
  56. int BuildFastZero(LONG fastexec,LONG ignore);
  57. int RemoveFastZero(void);
  58. ULONG ChipLowEnd(void);
  59. int KillFastZero(void);
  60. struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp);
  61. BOOL SetPages(struct MMUContext *ctx,ULONG props,ULONG lower,ULONG size,ULONG pagesize,ULONG dest);
  62. int MoveSSP(LONG size);
  63. int MoveVBR(void);
  64. int ClearVBR(void);
  65. void SuperStackSwap(UBYTE *newstack,ULONG size);
  66. ///
  67. /// Strukturen
  68. struct FastZeroPort {
  69.         struct MsgPort          frp_Port;
  70.         UWORD                   frp_cludgefill;
  71.         void                   *frp_Logical;            /* Logical position this is remapped to */
  72.         void                   *frp_Physical;           /* Physical location of the RAM used for remapping */
  73.         ULONG                   frp_Lower;              /* where remapping was started */
  74.         ULONG                   frp_Size;               /* size of the allocated memory */
  75.         struct Library         *frp_Base;               /* Keep the library open */
  76.         struct MemHeader       *frp_LowMemHeader;
  77.         ULONG                   frp_CacheFlags;         /* Keeps the caching mode for the remapping destination */
  78.         char                    frp_Name[32];           /* keeps the name of the port */
  79.  
  80.         struct Library         *frp_MMUBase;
  81.         APTR                    frp_OldSumKickData;     /* the old function to sum up the resident kicks */
  82. };
  83.  
  84. /* This is the port build by MuMove4k */
  85.  
  86. struct MuMove4KPort {
  87.         struct MsgPort          mrp_Port;
  88.         UWORD                   mrp_cludgefill;
  89.         void                   *mrp_private;
  90.         struct MemHeader       *mrp_LowMemHeader;
  91.         ULONG                   mrp_UpperEnd;
  92. };
  93.  
  94.  
  95. struct FastVBRPort {
  96.         struct MsgPort          fvp_Port;
  97.         char                    fvp_Name[30];           /* Keeps the name of the port, and aligns it */
  98.         ULONG                   fvp_Vectors[0x100];
  99. };
  100.  
  101. ///
  102. /// Externals
  103. extern void __asm CopyMMULess(register __a1 void *to,register __a0 void *from,register __d0 ULONG size);
  104. extern ULONG __asm *GetVBR(void);
  105. extern void __asm SetVBR(register __a0 ULONG *vbr);
  106. extern ULONG __asm NewSumKickData(void);
  107. extern void __asm NewSumKickDataEnd(void);
  108. ///
  109.  
  110. char version[]="$VER: MuFastZero " STRINGVERSION " (" STRINGDATE ") © THOR";
  111.  
  112. /// main
  113. int __asm __saveds main(void)
  114. {
  115. LONG args[OPT_COUNT];
  116. struct RDArgs *rd,*myrd;
  117. struct Process *proc;
  118. int rc=20;
  119. LONG err;
  120. struct WBStartup *msg;
  121. BPTR oldout;
  122. struct MsgPort *oldconsole;
  123. LONG stack;
  124.  
  125.  
  126.         SysBase=*((struct ExecBase **)(4L));
  127.  
  128.         memset(args,0,sizeof(LONG)*OPT_COUNT);
  129.         /* Wait for the workbench startup, if any */
  130.         proc=(struct Process *)FindTask(NULL);
  131.  
  132.         if (!(proc->pr_CLI)) {
  133.                 WaitPort(&(proc->pr_MsgPort));
  134.                 msg=(struct WBStartup *)GetMsg(&(proc->pr_MsgPort));
  135.         } else  msg=NULL;
  136.  
  137.         if (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37L)) {
  138.                 if (MMUBase=(struct MMUBase *)OpenLibrary("mmu.library",41L)) {
  139.  
  140.                         myrd=NULL;      /* reset the temporary ReadArgs */
  141.                         oldout=NULL;
  142.                         oldconsole=NULL;
  143.                         if (msg) {
  144.                                 oldout=SelectOutput(NULL);
  145.                                 oldconsole=SetConsoleTask(NULL);
  146.                                 rd=ReadTTArgs(msg,args,&myrd);
  147.                         } else  rd=ReadArgs(TEMPLATE,args,NULL);
  148.  
  149.                         if (rd) {
  150.                                 if (!GetMMUType()) {
  151.                                         Printf("MuFastZero requires a working MMU.\n");
  152.                                         err=10;
  153.                                 } else {
  154.                                         /* Argument parser worked, call main routine */
  155.                                         err=0;
  156.  
  157.                                         if (args[OPT_FORCENATIVE])
  158.                                                 err=KillFastZero();
  159.  
  160.                                         if (err<10 && ((args[OPT_ON]) || ((!args[OPT_OFF]) && (!args[OPT_FASTSSP])
  161.                                                     && (!args[OPT_FASTVBR]) && (!args[OPT_CLEARVBR]))))
  162.                                                         err=BuildFastZero(args[OPT_FASTEXEC],args[OPT_IGNORE]);
  163.  
  164.                                         if (err<10 && args[OPT_OFF])
  165.                                                 err=RemoveFastZero();
  166.  
  167.                                         if (err<10 && args[OPT_FASTSSP]) {
  168.                                                 if (args[OPT_STACKSIZE]) {
  169.                                                         stack=*(LONG *)args[OPT_STACKSIZE];
  170.                                                 } else  stack=0;
  171.                                                 err=MoveSSP(stack);
  172.                                         }
  173.  
  174.                                         if (err<10 && args[OPT_CLEARVBR]) {
  175.                                                 err=ClearVBR();
  176.                                         }
  177.  
  178.                                         if (err<10 && args[OPT_FASTVBR]) {
  179.                                                 err=MoveVBR();
  180.                                         }
  181.                                 }
  182.  
  183.                                 FreeArgs(rd);
  184.                                 if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  185.                                 if (msg)  Close(SelectOutput(NULL));
  186.                         } else  err=IoErr();
  187.  
  188.                         if (msg) {
  189.                                 SelectOutput(oldout);
  190.                                 SetConsoleTask(oldconsole);
  191.                         }
  192.  
  193.                         if (err<64) {
  194.                                 rc=err;
  195.                                 err=0;
  196.                         } else {
  197.                                 if (!msg) PrintFault(err,"MuFastZero failed");
  198.                                 rc=10;
  199.                         }
  200.                         SetIoErr(err);
  201.  
  202.                         CloseLibrary((struct Library *)MMUBase);
  203.                 } else if (!msg) PrintFault(ERROR_OBJECT_NOT_FOUND,"MuFastZero requires the mmu.library V41 or better");
  204.                 CloseLibrary((struct Library *)DOSBase);
  205.         }
  206.  
  207.         if (msg) {
  208.                 Forbid();
  209.                 ReplyMsg((struct Message *)msg);
  210.         }
  211.  
  212.         return rc;
  213. }
  214. ///
  215. /// ReadTTArgs
  216. struct RDArgs *ReadTTArgs(struct WBStartup *msg,LONG args[],struct RDArgs **tmp)
  217. {
  218. struct WBArg *wbarg;
  219. struct DiskObject *dop;
  220. char **tt;                      /* ToolTypes array */
  221. char *wbstr;                    /* Our self-made workbench argument string */
  222. char *here;
  223. BPTR oldlock;
  224. ULONG len;
  225. struct RDArgs *rd=NULL,*myrd=NULL;
  226. LONG err=0;
  227. BPTR newout;
  228.  
  229.         if (IconBase=OpenLibrary("icon.library",37L)) {
  230.                 if (wbarg=msg->sm_ArgList) {
  231.                         /* use a project icon if there is one... */
  232.                         if (msg->sm_NumArgs > 1) wbarg++;
  233.  
  234.                         /* go into the directory */
  235.                         oldlock=CurrentDir(wbarg->wa_Lock);
  236.  
  237.                         if (dop=GetDiskObject(wbarg->wa_Name)) {
  238.                                 if (tt=dop->do_ToolTypes) {
  239.                                         /* Read a special tool type for the output window */
  240.  
  241.                                         /* Calc the size of the argument string */
  242.  
  243.                                         len = 3;        /* reserve space for SPC,LF,NUL */
  244.                                         while (*tt) {
  245.                                                 len += strlen(*tt)+1;   /* string, plus space */
  246.                                                 tt++;
  247.                                         }
  248.  
  249.                                         if (wbstr=AllocVec(len,MEMF_PUBLIC)) {
  250.                                                 /* Now copy the arguments into this string, one by one
  251.                                                    and check whether the argument string is still valid. */
  252.  
  253.                                                 tt=dop->do_ToolTypes;
  254.                                                 here=wbstr;
  255.                                                 do{
  256.                                                         *here='\0';                     /* terminate string */
  257.                                                         /* Check whether this tool type is
  258.                                                            commented out. Just ignore it in this case */
  259.                                                         if (*tt) {
  260.                                                                 if (**tt=='(' || **tt==';')
  261.                                                                         continue;
  262.  
  263.                                                                 strcpy(here,*tt);      /* Add TT string */
  264.                                                         }
  265.                                                         len=strlen(here);
  266.                                                         here[len]='\n';
  267.                                                         here[len+1]='\0';               /* terminate string */
  268.  
  269.                                                         /* Now try to ReadArg' this string */
  270.  
  271.                                                         /* release old arguments left over from last loop */
  272.                                                         if (rd) FreeArgs(rd);
  273.                                                         if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  274.                                                         rd=NULL;
  275.                                                         memset(args,0,sizeof(LONG)*OPT_COUNT);
  276.  
  277.                                                         if (myrd=AllocDosObject(DOS_RDARGS,NULL)) {
  278.                                                                 /* Allocate and setup the ReadArgs source */
  279.                                                                 myrd->RDA_Source.CS_Buffer=wbstr;
  280.                                                                 myrd->RDA_Source.CS_Length=strlen(wbstr);
  281.  
  282.                                                                 if (rd=ReadArgs(TEMPLATE ",WINDOW/K",args,myrd)) {
  283.                                                                         /* Is this still valid? */
  284.                                                                         here[len]=' ';
  285.                                                                         here+=len+1;
  286.                                                                         /* if so, accept this argument and go on */
  287.                                                                 } else {
  288.                                                                         err=IoErr();
  289.                                                                         if (err==ERROR_NO_FREE_STORE) break;
  290.                                                                         else    err=0;  /* Ignore unknown or invalid arguments silently */
  291.                                                                 }
  292.                                                         } else {
  293.                                                                 err=ERROR_NO_FREE_STORE;
  294.                                                                 break;
  295.                                                         }
  296.                                                 }while(*tt++);
  297.  
  298.                                                 FreeVec(wbstr);
  299.                                         } else err=ERROR_NO_FREE_STORE;
  300.                                 } else err=ERROR_REQUIRED_ARG_MISSING; /* Huh, how should this happen ? */
  301.                                 FreeDiskObject(dop);
  302.                         } else err=IoErr();
  303.                         CurrentDir(oldlock);
  304.                 } else err=ERROR_REQUIRED_ARG_MISSING; /* This should not happen either */
  305.                 CloseLibrary(IconBase);
  306.         } else err=ERROR_OBJECT_NOT_FOUND;    /* This should not happen */
  307.  
  308.         /* Open an output stream */
  309.  
  310.         if (err==0) {
  311.                 if (newout=Open((args[OPT_WINDOW])?((char *)args[OPT_WINDOW]):("NIL:"),MODE_NEWFILE)) {
  312.                         SelectOutput(newout);
  313.                         /* Hack in the output console. Well, well... */
  314.                         SetConsoleTask(((struct FileHandle *)(BADDR(newout)))->fh_Type);
  315.                 } else err=IoErr();
  316.         }
  317.  
  318.         if (err) {
  319.                 if (rd)   FreeArgs(rd);
  320.                 if (myrd) FreeDosObject(DOS_RDARGS,myrd);
  321.                 SetIoErr(err);
  322.                 rd=NULL;
  323.                 myrd=NULL;
  324.         }
  325.  
  326.         *tmp=myrd;
  327.         return rd;
  328. }
  329. ///
  330. /// SetPages
  331. BOOL SetPages(struct MMUContext *ctx,ULONG props,ULONG lower,ULONG size,ULONG pagesize,ULONG dest)
  332. {
  333. ULONG pages,i;
  334. ULONG base;
  335.  
  336.         pages=size/pagesize;
  337.         base=0;
  338.         for(i=0;i<pages;i++) {
  339.                 if (!SetPageProperties(ctx,props,~0L,lower+base,MAPTAG_DESTINATION,dest+base,TAG_DONE))
  340.                         return FALSE;
  341.                 base+=pagesize;
  342.         }
  343.  
  344.         return TRUE;
  345. }
  346. ///
  347. /// BuildFastZero
  348. int BuildFastZero(LONG fastexec,LONG ignore)
  349. {
  350. void *mem=NULL,*pmem=NULL;
  351. ULONG portsize,codesize;
  352. ULONG pagesize,size,psize,align;
  353. ULONG lower;
  354. struct FastZeroPort *port;
  355. struct MuMove4KPort *mport;
  356. struct MMUContext *ctx,*sctx;   /* default context, supervisorcontext */
  357. struct MinList *ctxl,*sctxl;    /* Copies of the mappings currently active */
  358. int err=ERROR_NO_FREE_STORE;
  359. ULONG props,cacheflags;
  360. BOOL retry;
  361.  
  362.  
  363.         Forbid();                               /* Shut up PatchWork */
  364.  
  365.         /* If this is already installed, warn and return. */
  366.  
  367.         if (FindPort("« MuFastZero »")) {
  368.                 Permit();
  369.                 Printf("MuFastZero already running.\n");
  370.                 return 5;
  371.         }
  372.  
  373.         Permit();
  374.  
  375.         ctx=DefaultContext();   /* get the default context */
  376.         sctx=SuperContext(ctx); /* get the supervisor context for this one */
  377.  
  378.         /* Read the size */
  379.         pagesize=GetPageSize(ctx);
  380.  
  381.         /*
  382.         size = pagesize;
  383.         */
  384.         size = ChipLowEnd() & -pagesize;
  385.  
  386.         if (size>ChipLowEnd()) {
  387.                 size=0;
  388.         }
  389.         align=RemapSize(ctx);
  390.  
  391.         if (fastexec) {
  392.                 ULONG infast = 1;
  393.                 struct Library *ExpansionBase=NULL;
  394.  
  395.                 Forbid();
  396.                 mport=(struct MuMove4KPort *)FindPort("« MuMove4K »");
  397.                 if (mport) {
  398.                         size=mport->mrp_UpperEnd;
  399.                 }
  400.                 Permit();
  401.  
  402.                 ExpansionBase = OpenLibrary("expansion.library",0);
  403.                 if (ExpansionBase) {
  404.                         if ((TypeOfMem(ExpansionBase) & MEMF_FAST) == 0)
  405.                                 infast = 0;
  406.                         CloseLibrary(ExpansionBase);
  407.                 }
  408.                 if ((TypeOfMem(SysBase) & MEMF_FAST) == 0)
  409.                         infast = 0;
  410.  
  411.                 if (infast) {
  412.                         Printf("ExecBase is already in fast memory, can't remap ExecBase.\n");
  413.                         return 10;
  414.                 }
  415.  
  416.                 if (mport==NULL) {
  417.                         Printf("MuMove4K is not installed, can't remap ExecBase.\n");
  418.                         return 10;
  419.                 }
  420.         } else mport=NULL;
  421.  
  422.         if (size==0) {
  423.                 Printf("The MMU page size is too large for MuFastZero.\n");
  424.                 return 10;
  425.         }
  426.  
  427.         codesize = (ULONG)(&NewSumKickDataEnd) - (ULONG)(&NewSumKickData);
  428.         portsize = sizeof(struct FastZeroPort) + codesize;
  429.         port     = AllocVec(portsize,MEMF_CLEAR|MEMF_PUBLIC);
  430.         if (port) {
  431.  
  432.          memcpy(port+1,&NewSumKickData,(size_t)codesize);
  433.  
  434.          /* Lock the context, make sure nobody is messing with the memory */
  435.          LockContextList();      /* We've to lock the list first, we want to lock more than one */
  436.          LockMMUContext(ctx);
  437.          LockMMUContext(sctx);
  438.          err=0;
  439.  
  440.          /* Read the properties of the zeropage. If this is either invalid
  441.             or already remapped, don't touch. */
  442.  
  443.          lower=0;
  444.  
  445.          do {
  446.  
  447.                 retry=FALSE;
  448.                 props=GetPageProperties(ctx,lower,TAG_DONE);
  449.                 props|=GetPageProperties(sctx,lower,TAG_DONE);
  450.  
  451.                 if ((props & MAPP_INVALID) || (props & MAPP_SWAPPED) ||
  452.                     (props & MAPP_SUPERVISORONLY)) {
  453.  
  454.                         if (fastexec && (size>pagesize)) {
  455.                                 size-=pagesize;
  456.                                 lower+=pagesize;
  457.                                 retry=TRUE;
  458.                         } else {
  459.                                 Printf("The zero page is invalidated and can't be remapped.\n");
  460.                                 err=10;
  461.                         }
  462.                 }
  463.          } while(retry);
  464.  
  465.          if ((props & MAPP_REMAPPED) && (err==0)) {
  466.                 if (!ignore) {
  467.                         Printf("The zero page is already remapped.\n"
  468.                                "In case you want to disable remapping, or want to use the\n"
  469.                                "FASTEXEC option, specify FORCENATIVE to override the\n"
  470.                                "remapping.\n");
  471.                                 err=10;
  472.                 } else err=2;
  473.          }
  474.  
  475.          if (err==0L) {
  476.  
  477.           /* We request FAST here, explicitly. Taking chip memory for the
  478.              image doesn't make sense, this isn't fast either... */
  479.  
  480.           mem=AllocAligned(size+lower,MEMF_PUBLIC|MEMF_FAST|MEMF_CLEAR,align);
  481.           if (mem) {
  482.            psize=size+lower;
  483.            pmem=mem;
  484.            PhysicalLocation(ctx,&pmem,&psize);
  485.            if (psize!=size+lower) {
  486.                 Printf("The allocated memory is fragmentated, unsupported by MuFastZero.\n");
  487.                 err=10;
  488.            }
  489.           } else err=ERROR_NO_FREE_STORE;
  490.          }
  491.  
  492.          if (err==0L) {
  493.  
  494.             cacheflags=GetProperties(ctx,(ULONG)mem,TAG_DONE) & CACHEFLAGS;
  495.  
  496.             /* Make a copy of the software levels to be able to restore
  497.                them later in case of an error. */
  498.  
  499.             if (ctxl=GetMapping(ctx)) {
  500.              if (sctxl=GetMapping(sctx)) {
  501.  
  502.               /* Modify both contexts such that the zeropage is SINGLE.
  503.                  This operation is very costy, but it doesn't matter
  504.                  except for speed penalties if this is not un-done */
  505.  
  506.               err=ERROR_NO_FREE_STORE;
  507.               props=MAPP_SINGLEPAGE;
  508.  
  509.               if (SetProperties(ctx,props,props,lower,size,TAG_DONE)) {
  510.                if (SetProperties(sctx,props,props,lower,size,TAG_DONE)) {
  511.                 if (RebuildTrees(ctx,sctx,NULL)) {
  512.  
  513.                   /* Copy the zeropage over */
  514.                   Disable();
  515.  
  516.                   /* Fill in SysBase at location 4 */
  517.                   ((ULONG *)mem)[1]=(ULONG)SysBase;
  518.                   memcpy((char *)mem+lower,(char *)lower,(size_t)size);
  519.  
  520.                   /* The new property flags, or in the cache flags */
  521.                   props=MAPP_REMAPPED|MAPP_SINGLEPAGE|cacheflags;
  522.                   CacheClearU();
  523.  
  524.                   /* Map in the properties immediately. This should always work,
  525.                      except the parameters are invalid - which they aren't.
  526.                      This extra step is required because all other calls might
  527.                      break the Disable() above. */
  528.                   if (SetPages(ctx,props,lower,size,pagesize,(ULONG)pmem+lower)) {
  529.                    if (SetPages(sctx,props,lower,size,pagesize,(ULONG)pmem+lower)) {
  530.  
  531.                     /* Tell the contexts to relocate the zero page even in case MuForce
  532.                        is installed later, i.e. the software emulation should read
  533.                        the data from the relocated position, not from the original. */
  534.  
  535.                     SetMMUContextData(ctx,MCXTAG_ZEROBASE,pmem,TAG_DONE);
  536.                     SetMMUContextData(sctx,MCXTAG_ZEROBASE,pmem,TAG_DONE);
  537.  
  538.                     /* Now make the modifications in the abstraction level. */
  539.                     if (SetProperties(ctx,props,~0L,lower,size,MAPTAG_DESTINATION,(ULONG)pmem+lower,TAG_DONE)) {
  540.                      if (SetProperties(sctx,props,~0L,lower,size,MAPTAG_DESTINATION,(ULONG)pmem+lower,TAG_DONE)) {
  541.  
  542.                         /* The modifications in the hardware level are actually already done.
  543.                            Calling RebuildTree isn't stricly required here, but we do it
  544.                            anyways to clear the dirty flags. This might or might not fail,
  545.                            but the resulting MMU trees are always what we want. In
  546.                            case it fails, the dirty flags are set. So what... */
  547.  
  548.                         /* The RebuildTree's are below... */
  549.  
  550.                         /* Everything worked fine so far.... */
  551.                         port->frp_Port.mp_Node.ln_Type=NT_MSGPORT;
  552.                         port->frp_Port.mp_Node.ln_Name=port->frp_Name;
  553.                         port->frp_Port.mp_Node.ln_Pri=-100;
  554.                         strcpy(port->frp_Name,"« MuFastZero »");
  555.                         port->frp_Port.mp_Flags=PA_IGNORE;
  556.                         NewList(&(port->frp_Port.mp_MsgList));
  557.  
  558.                         port->frp_Physical=pmem;
  559.                         port->frp_Logical=mem;
  560.                         port->frp_Size=size;
  561.                         port->frp_Lower=lower;
  562.                         port->frp_CacheFlags=cacheflags;
  563.                         if (mport) {
  564.                                 port->frp_LowMemHeader=mport->mrp_LowMemHeader;
  565.                                 port->frp_LowMemHeader->mh_Attributes=MEMF_FAST;   /* remove the chip and public attributes */
  566.                         }
  567.  
  568.                         port->frp_Base=OpenLibrary("mmu.library",0L);
  569.                         port->frp_MMUBase = port->frp_Base;
  570.                         Disable();
  571.                         port->frp_OldSumKickData = SetFunction((struct Library *)SysBase,LVO_SUMKICKDATA,(APTR)(port+1));
  572.                         AddPort(&(port->frp_Port));
  573.                         Enable();
  574.  
  575.                         /* We're done here. Fine. */
  576.                         err=0;
  577.                         mem=NULL;
  578.                         port=NULL;
  579.  
  580.                      }
  581.                     }
  582.  
  583.                    /* We can't set the software level. Urgh. At least, we can
  584.                       restore it how it looked like before. */
  585.                    }
  586.                   }
  587.  
  588.                   /* We try to restore the hardware tables now. */
  589.                   if (err) {
  590.                         props=MAPP_IMPRECISE|MAPP_NONSERIALIZED|MAPP_CACHEINHIBIT|MAPP_SINGLEPAGE;
  591.  
  592.                         if ((!SetPageProperties(ctx,props,~0L,0L,TAG_DONE)) ||
  593.                             (!SetPageProperties(sctx,props,~0L,0L,TAG_DONE))) {
  594.                                 /* We can't restore the hardware tables either! */
  595.                                 Alert(0xbe000101);
  596.                                 /* Sorry, go guru. We can't do much more here... */
  597.                         }
  598.                   }
  599.                   Enable();
  600.                 }
  601.                }
  602.               }
  603.  
  604.               /* We can't build the software level. In the one way or the other,
  605.                  just restore the previous software abstraction level. */
  606.  
  607.               if (err) {
  608.                 SetPropertyList(ctx,ctxl);
  609.                 SetPropertyList(sctx,sctxl);
  610.               }
  611.  
  612.               /* The software level is now restored. The
  613.                  hardware level has been restored above.
  614.                  Now call RebuildTree() to clear the dirty
  615.                  flags.
  616.                  If this fails, tough luck. Both levels are
  617.                  actually fine, except for the busy flags. */
  618.  
  619.               RebuildTrees(ctx,sctx,NULL);
  620.  
  621.               ReleaseMapping(sctx,sctxl);
  622.              }
  623.              ReleaseMapping(ctx,ctxl);
  624.             }
  625.          }
  626.  
  627.            /* Release the locks */
  628.          UnlockMMUContext(sctx);
  629.          UnlockMMUContext(ctx);
  630.          UnlockContextList();
  631.  
  632.          if (mem) FreeMem(mem,size+lower);
  633.          if (port) FreeVec(port);
  634.         }
  635.  
  636.         return err;
  637. }
  638. ///
  639. /// RemoveFastZero
  640. int RemoveFastZero(void)
  641. {
  642. struct MMUContext *ctx,*sctx;
  643. struct MinList *ctxl,*sctxl;
  644. struct FastZeroPort *port;
  645. ULONG size,pagesize,lower;
  646. void *mem,*pmem;
  647. ULONG props,cacheflags;
  648. int err;
  649.  
  650.         Forbid();                               /* Shut up PatchWork */
  651.  
  652.         /* If this is not installed, warn and return. */
  653.  
  654.         port=(struct FastZeroPort *)FindPort("« MuFastZero »");
  655.  
  656.         if (port==NULL) {
  657.                 Permit();
  658.                 Printf("MuFastZero not installed.\n");
  659.                 return 5;
  660.         }
  661.         /* Remove it, to ensure nobody else tries to remove it */
  662.         RemPort(&(port->frp_Port));
  663.         Permit();
  664.  
  665.         ctx=DefaultContext();   /* get the default context */
  666.         sctx=SuperContext(ctx); /* get the supervisor context for this one */
  667.  
  668.         pagesize=GetPageSize(ctx);
  669.         if (GetPageSize(sctx)!=pagesize) {
  670.                 Printf("Supervisor and user page size are different,\n"
  671.                        "MuFastZero can't be removed.\n");
  672.                 return 10;
  673.         }
  674.  
  675.         LockContextList();      /* We've to lock the list first, we want to lock more than one */
  676.         LockMMUContext(ctx);
  677.         LockMMUContext(sctx);
  678.  
  679.         err=ERROR_NO_FREE_STORE;
  680.  
  681.         /* Make a copy of the mapping like it is now */
  682.         if (ctxl=GetMapping(ctx)) {
  683.          if (sctxl=GetMapping(sctx)) {
  684.  
  685.           /* Read the properties of the zeropage. If this is either invalid
  686.              or already remapped, don't touch. */
  687.  
  688.           lower=port->frp_Lower;
  689.           props=GetPageProperties(ctx,lower,TAG_DONE);
  690.           props|=GetPageProperties(sctx,lower,TAG_DONE);
  691.           err=0;
  692.  
  693.           if ((props & MAPP_INVALID) || (props & MAPP_SWAPPED) ||
  694.               (props & MAPP_SUPERVISORONLY)) {
  695.                 Printf("The zero page is now invalidated and can't be restored for that reason.\n");
  696.                 err=10;
  697.           }
  698.  
  699.           if ((err==0) && ((props & MAPP_REMAPPED)==0)) {
  700.                 Printf("The zero page is no longer remapped to FastMem.\n");
  701.                 err=10;
  702.           }
  703.  
  704.           /* If everything is fine so far, start removing things */
  705.           if (err==0) {
  706.            size=port->frp_Size;
  707.            pmem=port->frp_Physical;
  708.            mem=port->frp_Logical;
  709.            lower=port->frp_Lower;
  710.            cacheflags=port->frp_CacheFlags;
  711.            Disable();
  712.  
  713.            err=ERROR_NO_FREE_STORE;
  714.            props=MAPP_NONSERIALIZED|MAPP_IMPRECISE|MAPP_CACHEINHIBIT|MAPP_SINGLEPAGE;       /* This is the only flag for chip memory */
  715.  
  716.            /* Now copy the data back to the zeropage */
  717.            CopyMMULess((char *)lower,(char *)pmem+lower,size);
  718.  
  719.            /* First, try to modify the hardware tables. */
  720.            if (SetPages(ctx,props,lower,size,pagesize,lower)) {
  721.             if (SetPages(sctx,props,lower,size,pagesize,lower)) {
  722.  
  723.              /* read the data again from the real stuff */
  724.              SetMMUContextData(ctx,MCXTAG_ZEROBASE,0L,TAG_DONE);
  725.              SetMMUContextData(sctx,MCXTAG_ZEROBASE,0L,TAG_DONE);
  726.  
  727.              /* Restore the software level,singlepage is no longer required */
  728.  
  729.              props=MAPP_NONSERIALIZED|MAPP_IMPRECISE|MAPP_CACHEINHIBIT;
  730.              if (SetProperties(ctx,props,~0L,lower,size,TAG_DONE)) {
  731.               if (SetProperties(sctx,props,~0L,lower,size,TAG_DONE)) {
  732.  
  733.                         if (port->frp_LowMemHeader) {
  734.                                 /* No, neither public nor anything else */
  735.                                 port->frp_LowMemHeader->mh_Attributes=MEMF_CHIP;
  736.                         }
  737.  
  738.                         Forbid();
  739.                         SetFunction((struct Library *)SysBase,LVO_SUMKICKDATA,port->frp_OldSumKickData);
  740.                         Permit();
  741.                         FreeMem(mem,size+lower);
  742.                         if (port->frp_Base)
  743.                                 CloseLibrary(port->frp_Base);
  744.  
  745.                         FreeVec(port);
  746.                         err=0;
  747.               }
  748.              }
  749.  
  750.               /* We can't setup the software level. Urgh. At least,
  751.                  we should try to set things back how they used to be. */
  752.             }
  753.            }
  754.  
  755.  
  756.            /* We try to restore the hardware tables now. */
  757.            if (err) {
  758.                 props=MAPP_REMAPPED|MAPP_SINGLEPAGE|cacheflags;
  759.                 SetMMUContextData(ctx,MCXTAG_ZEROBASE,(ULONG)pmem+lower,TAG_DONE);
  760.                 SetMMUContextData(sctx,MCXTAG_ZEROBASE,(ULONG)pmem+lower,TAG_DONE);
  761.  
  762.                 if ((!SetPages(ctx,props,lower,size,pagesize,(ULONG)pmem+lower)) ||
  763.                     (!SetPages(sctx,props,lower,size,pagesize,(ULONG)pmem+lower))) {
  764.                         /* We can't restore the hardware tables either! */
  765.                         Alert(0xbe000101);
  766.                         /* Sorry, go guru. We can't do much more here... */
  767.                 }
  768.            }
  769.            Enable();
  770.  
  771.            if (err) {
  772.                 SetPropertyList(ctx,ctxl);
  773.                 SetPropertyList(sctx,sctxl);
  774.                 /* More luck next time */
  775.                 AddPort(&(port->frp_Port));
  776.            }
  777.  
  778.              /* The software level is now restored. The
  779.                 hardware level has been restored above.
  780.                 Now call RebuildTree() to clear the dirty
  781.                 flags.
  782.                 If this fails, tough luck. Both levels are
  783.                 actually fine, except for the busy flags. */
  784.  
  785.            RebuildTrees(ctx,sctx,NULL);
  786.           }
  787.           ReleaseMapping(sctx,sctxl);
  788.          }
  789.          ReleaseMapping(ctx,ctxl);
  790.         }
  791.  
  792.  
  793.         UnlockMMUContext(sctx);
  794.         UnlockMMUContext(ctx);
  795.         UnlockContextList();      /* We've to lock the list first, we want to lock more than one */
  796.  
  797.         if (err) {
  798.                 /* Uhoh, things didn't work here... */
  799.                 Printf("Can't remove the FastZero node, sorry.\n");
  800.         }
  801.  
  802.         return err;
  803. }
  804. ///
  805. /// KillFastZero
  806. int KillFastZero(void)
  807. {
  808. struct FastZeroPort *port;
  809. struct MMUContext *ctx,*sctx;   /* default context, supervisorcontext */
  810. struct MinList *ctxl,*sctxl;    /* Copies of the mappings currently active */
  811. ULONG pagesize;
  812. ULONG lower,size,props;
  813. ULONG userpos,superpos,base;
  814. int err;
  815. BOOL retry;
  816.  
  817.  
  818.         Forbid();                               /* Shut up PatchWork */
  819.  
  820.         /* If MuFastZero is installed, remove it the easy way */
  821.  
  822.         port=(struct FastZeroPort *)FindPort("« MuFastZero »");
  823.  
  824.         if (port) {
  825.                 Permit();
  826.                 return RemoveFastZero();
  827.         }
  828.  
  829.         Permit();
  830.  
  831.         ctx=DefaultContext();   /* get the default context */
  832.         sctx=SuperContext(ctx); /* get the supervisor context for this one */
  833.  
  834.         /* Read the size */
  835.         pagesize=GetPageSize(ctx);
  836.  
  837.         if (GetPageSize(sctx)!=pagesize) {
  838.                 Printf("Supervisor and user page size are different,\n"
  839.                        "MuFastZero failed.\n");
  840.                 return 10;
  841.         }
  842.  
  843.         /* Lock the context, make sure nobody is messing with the memory */
  844.         LockContextList();      /* We've to lock the list first, we want to lock more than one */
  845.         LockMMUContext(ctx);
  846.         LockMMUContext(sctx);
  847.         err=0;
  848.  
  849.         /* Read the properties of the zeropage. If this is either invalid
  850.            or not remapped, don't touch. */
  851.  
  852.         lower=0;
  853.         size=0;
  854.         base=0;
  855.  
  856.         do {
  857.  
  858.                 retry=FALSE;
  859.                 userpos=superpos=0;
  860.                 props=GetPageProperties(ctx,lower+size,
  861.                                         MAPTAG_DESTINATION,&userpos,
  862.                                         TAG_DONE);
  863.                 props|=GetPageProperties(sctx,lower+size,
  864.                                          MAPTAG_DESTINATION,&superpos,
  865.                                          TAG_DONE);
  866.  
  867.                 if ((props & MAPP_INVALID) || (props & MAPP_SWAPPED) ||
  868.                     (props & MAPP_SUPERVISORONLY)) {
  869.  
  870.                         lower += pagesize;
  871.                         retry = TRUE;
  872.  
  873.                 } else if (props & MAPP_REMAPPED) {
  874.                         if (userpos == superpos) {
  875.  
  876.                                 if (base==0) {
  877.                                         base = userpos;
  878.                                 }
  879.                                 /* Adjacent? */
  880.                                 if (base+size == userpos) {
  881.                                         size += pagesize;
  882.                                         retry = TRUE;
  883.                                 }
  884.                         }
  885.                 }
  886.  
  887.         } while(retry);
  888.  
  889.         if (size==0L) {
  890.                 Printf("MuFastZero: FORCENATIVE option is not required.\n");
  891.                 err = 5;
  892.         }
  893.  
  894.          /* lower is now the lower end which is remapped.
  895.             size is the length of the remapped memory
  896.             base is the address it is remapped to */
  897.  
  898.         if (err==0L) {
  899.  
  900.          /* Make a copy of the software levels to be able to restore
  901.             them later in case of an error. */
  902.  
  903.          if (ctxl=GetMapping(ctx)) {
  904.           if (sctxl=GetMapping(sctx)) {
  905.  
  906.            /* Modify both contexts such that the zeropage is SINGLE.
  907.               This operation is very costy, but it doesn't matter
  908.               except for speed penalties if this is not un-done */
  909.  
  910.               err=ERROR_NO_FREE_STORE;
  911.               props=MAPP_SINGLEPAGE;
  912.  
  913.            if (SetProperties(ctx,props,props,lower,size,TAG_DONE)) {
  914.             if (SetProperties(sctx,props,props,lower,size,TAG_DONE)) {
  915.              if (RebuildTrees(ctx,sctx,NULL)) {
  916.  
  917.                Disable();
  918.  
  919.                /* The new property flags */
  920.                props=MAPP_NONSERIALIZED|MAPP_IMPRECISE|MAPP_SINGLEPAGE|MAPP_CACHEINHIBIT;
  921.                CacheClearU();
  922.                CopyMMULess((void *)lower,(void *)base,size);
  923.  
  924.                /* Map in the properties immediately. This should always work,
  925.                   except the parameters are invalid - which they aren't.
  926.                   This extra step is required because all other calls might
  927.                   break the Disable() above. */
  928.  
  929.                if (SetPages(ctx,props,lower,size,pagesize,0L)) {
  930.                 if (SetPages(sctx,props,lower,size,pagesize,0L)) {
  931.  
  932.                  /* Tell the contexts not to relocate the zero page even in case MuForce
  933.                     is installed later, i.e. the software emulation should read
  934.                     the data from the relocated position, not from the original. */
  935.  
  936.                  SetMMUContextData(ctx,MCXTAG_ZEROBASE,0L,TAG_DONE);
  937.                  SetMMUContextData(sctx,MCXTAG_ZEROBASE,0L,TAG_DONE);
  938.  
  939.                  /* Now make the modifications in the abstraction level. */
  940.                  if (SetProperties(ctx,props,~0L,lower,size,TAG_DONE)) {
  941.                   if (SetProperties(sctx,props,~0L,lower,size,TAG_DONE)) {
  942.  
  943.                         /* The modifications in the hardware level are actually already done.
  944.                            Calling RebuildTree isn't stricly required here, but we do it
  945.                            anyways to clear the dirty flags. This might or might not fail,
  946.                            but the resulting MMU trees are always what we want. In
  947.                            case it fails, the dirty flags are set. So what... */
  948.  
  949.                         /* We're done here. Fine. */
  950.                         err=0;
  951.                   }
  952.                  }
  953.                  /* We can't set the software level. Urgh. At least, we can
  954.                     restore it how it looked like before. */
  955.                 }
  956.                } /* of if SetPages */
  957.  
  958.                /* We try to restore the hardware tables now. */
  959.                if (err) {
  960.                 props=MAPP_REMAPPED|MAPP_SINGLEPAGE|MAPP_COPYBACK;
  961.                 SetMMUContextData(ctx,MCXTAG_ZEROBASE,base,TAG_DONE);
  962.                 SetMMUContextData(sctx,MCXTAG_ZEROBASE,base,TAG_DONE);
  963.  
  964.                 if ((!SetPages(ctx,props,lower,size,pagesize,base)) ||
  965.                     (!SetPages(sctx,props,lower,size,pagesize,base))) {
  966.                         /* We can't restore the hardware tables either! */
  967.                         Alert(0xbe000101);
  968.                         /* Sorry, go guru. We can't do much more here... */
  969.                 }
  970.                }
  971.  
  972.                Enable();
  973.              }
  974.             }
  975.            } /* of if SetProperties() */
  976.  
  977.            /* We can't build the software level. In the one way or the other,
  978.               just restore the previous software abstraction level. */
  979.  
  980.            if (err) {
  981.                 SetPropertyList(ctx,ctxl);
  982.                 SetPropertyList(sctx,sctxl);
  983.            }
  984.  
  985.            /* The software level is now restored. The
  986.               hardware level has been restored above.
  987.               Now call RebuildTree() to clear the dirty
  988.               flags.
  989.               If this fails, tough luck. Both levels are
  990.               actually fine, except for the busy flags. */
  991.  
  992.            RebuildTrees(ctx,sctx,NULL);
  993.  
  994.            ReleaseMapping(sctx,sctxl);
  995.           } /* of if made copy */
  996.           ReleaseMapping(ctx,ctxl);
  997.          } /* of if made copy */
  998.         } /* of if (err==0) */
  999.  
  1000.           /* Release the locks */
  1001.         UnlockMMUContext(sctx);
  1002.         UnlockMMUContext(ctx);
  1003.         UnlockContextList();
  1004.  
  1005.         return err;
  1006. }
  1007. ///
  1008. /// ChipLowEnd
  1009. ULONG ChipLowEnd(void)
  1010. {
  1011. ULONG low;
  1012. struct MemHeader *head;
  1013.  
  1014.         low=0x00200000;         /* This is definitely the upper end of chip mem */
  1015.  
  1016.         Forbid();
  1017.         for(head=(struct MemHeader *)SysBase->MemList.lh_Head;
  1018.                    head->mh_Node.ln_Succ;
  1019.                    head=(struct MemHeader *)(head->mh_Node.ln_Succ)) {
  1020.                 if (head->mh_Attributes & MEMF_CHIP) {
  1021.                         if ((ULONG)(head->mh_Lower)<low) {
  1022.                                 low=(ULONG)(head->mh_Lower);
  1023.                         }
  1024.                 }
  1025.         }
  1026.         Permit();
  1027.  
  1028.         return low;
  1029. }
  1030. ///
  1031. /// MoveSSP
  1032. int MoveSSP(LONG stacksize)
  1033. {
  1034. ULONG minsize;
  1035. struct Task *task;
  1036. UBYTE *newstack;
  1037.  
  1038.         minsize=(UBYTE *)SysBase->SysStkUpper-(UBYTE *)SysBase->SysStkLower;
  1039.         if (stacksize<minsize) {
  1040.                 task=FindTask(NULL);
  1041.                 stacksize=(UBYTE *)(task->tc_SPUpper)-(UBYTE *)(task->tc_SPLower);
  1042.         }
  1043.         if (stacksize<minsize)
  1044.                 stacksize=minsize;
  1045.  
  1046.         /* Round this to two cache lines */
  1047.  
  1048.         stacksize += 0x1f;
  1049.         stacksize &= ~0x1f;
  1050.  
  1051.         /* This must be fast, or this function is a joke... */
  1052.         newstack=AllocMem(stacksize,MEMF_CLEAR|MEMF_PUBLIC|MEMF_FAST);
  1053.  
  1054.         if (newstack==NULL) {
  1055.                 return ERROR_NO_FREE_STORE;
  1056.         }
  1057.  
  1058.         SuperStackSwap(newstack,stacksize);
  1059.  
  1060.         return 0;
  1061. }
  1062. ///
  1063. /// SuperStackSwap
  1064. void SuperStackSwap(UBYTE *newstack,ULONG size)
  1065. {
  1066. UBYTE *oldsp,*newsp;
  1067. size_t oldsize;
  1068. UWORD sum;
  1069. UWORD *p;
  1070.  
  1071.         /* Yup, this is possible in C */
  1072.         Disable();
  1073.         oldsp=SuperState();
  1074.  
  1075.         /* copy the stack over to the upper limit */
  1076.         oldsize=(UBYTE *)(SysBase->SysStkUpper)-oldsp;
  1077.         if (oldsize>0 && oldsize<size) {
  1078.                 newsp=newstack+size-oldsize;
  1079.                 memcpy(newsp,oldsp,oldsize);
  1080.         } else  newsp=newstack+size;
  1081.         UserState(newsp);
  1082.  
  1083.         /* Now tell this exec! */
  1084.         SysBase->SysStkUpper=newstack+size;
  1085.         SysBase->SysStkLower=newstack;
  1086.  
  1087.         /* Recalculate the checksum */
  1088.         p=&SysBase->SoftVer;
  1089.         sum=0xffff;
  1090.         while(p<&SysBase->ChkSum)
  1091.                 sum -= *p++;
  1092.  
  1093.         SysBase->ChkSum=sum;
  1094.         Enable();
  1095.  
  1096. }
  1097. ///
  1098. /// MoveVBR
  1099. int MoveVBR(void)
  1100. {
  1101. ULONG *vbr;
  1102. struct FastVBRPort *fvp;
  1103. struct MsgPort *old;
  1104.  
  1105.  
  1106.         if ((SysBase->AttnFlags & AFF_68010)==0) {
  1107.                 Printf("MuFastZero failed: MoveVBR requires at least an 68010 or better.\n");
  1108.                 return 10;
  1109.         }
  1110.  
  1111.         vbr=GetVBR();
  1112.  
  1113.         if (TypeOfMem(vbr) & MEMF_FAST) {
  1114.                 Printf("The vector base register is already in fast memory.\n");
  1115.                 return 5;
  1116.         }
  1117.  
  1118.         if (fvp=AllocVec(sizeof(struct FastVBRPort),MEMF_PUBLIC | MEMF_FAST | MEMF_CLEAR)) {
  1119.  
  1120.                 fvp->fvp_Port.mp_Node.ln_Type   =       NT_MSGPORT;
  1121.                 fvp->fvp_Port.mp_Node.ln_Pri    =       -100;
  1122.                 fvp->fvp_Port.mp_Node.ln_Name   =       fvp->fvp_Name;
  1123.                 fvp->fvp_Port.mp_Flags          =       PA_IGNORE;
  1124.                 NewList(&(fvp->fvp_Port.mp_MsgList));
  1125.                 strcpy(fvp->fvp_Name,"« FastVBR »");
  1126.  
  1127.                 Forbid();
  1128.                 Disable();
  1129.                 memcpy(fvp->fvp_Vectors,GetVBR(),0x400);
  1130.                 CacheClearU();
  1131.                 SetVBR(fvp->fvp_Vectors);
  1132.                 Enable();
  1133.                 /* Check whether we have an old instance of us. Strange... */
  1134.                 old=FindPort("« FastVBR »");
  1135.  
  1136.                 if (old) {
  1137.                         RemPort(old);
  1138.                         FreeVec(old);
  1139.                 }
  1140.                 AddPort(&(fvp->fvp_Port));
  1141.                 Permit();
  1142.  
  1143.                 return 0;
  1144.         }
  1145.  
  1146.         return ERROR_NO_FREE_STORE;
  1147. }
  1148. ///
  1149. /// ClearVBR
  1150. int ClearVBR(void)
  1151. {
  1152. ULONG *vbr;
  1153. ULONG props;
  1154. struct MsgPort *old;
  1155.  
  1156.         if ((SysBase->AttnFlags & AFF_68010)==0) {
  1157.                 vbr = 0;
  1158.         } else  vbr = GetVBR();
  1159.  
  1160.         if (vbr == 0L) {
  1161.                 Printf("The vector base register is already cleared.\n");
  1162.                 return 5;
  1163.         }
  1164.  
  1165.         props = GetProperties(DefaultContext(),0L,TAG_DONE);
  1166.  
  1167.         if (props & (MAPP_INVALID | MAPP_SWAPPED | MAPP_SUPERVISORONLY | MAPP_WRITEPROTECTED)) {
  1168.                 Printf("The zero page is invalidated, can't reset the vector base.\n");
  1169.                 return 5;
  1170.         }
  1171.  
  1172.         /* Hence, re-set it */
  1173.         Forbid();
  1174.         Disable();
  1175.         /* Copy the vectors back */
  1176.         memcpy((void *)(8L),2L+GetVBR(),0x400-8L);
  1177.         CacheClearU();
  1178.         SetVBR(0L);
  1179.         Enable();
  1180.  
  1181.         old=FindPort("« FastVBR »");
  1182.  
  1183.         if (old) {
  1184.                 RemPort(old);
  1185.                 FreeVec(old);
  1186.         }
  1187.         Permit();
  1188.  
  1189.         return 0;
  1190. }
  1191. ///
  1192.  
  1193.